package com.adun.scheduler.context;

import com.adun.scheduler.ISchedulerJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * @author ZDF
 * @date 2025/8/15
 */
public class SchedulerJobLocalContext {
    private static final Logger log = LoggerFactory.getLogger(SchedulerJobLocalContext.class);

    private static final Map<String, ISchedulerJob> SCHEDULER_JOB_MAP = new ConcurrentHashMap<>();

    private static final Map<String, ScheduledTaskRegistrar> SCHEDULED_TASK_REGISTRAR_MAP = new ConcurrentHashMap<>();

    private static final Map<String, ScheduledExecutorService> SCHEDULED_EXECUTOR_SERVICE_MAP = new ConcurrentHashMap<>();


    public static Map<String, ScheduledExecutorService> getScheduledExecutorServiceMap() {
        return SCHEDULED_EXECUTOR_SERVICE_MAP;
    }

    public static Map<String, ScheduledTaskRegistrar> getScheduledTaskRegistrarMap() {
        return SCHEDULED_TASK_REGISTRAR_MAP;
    }

    public static List<ScheduledTaskRegistrar> getScheduledTaskRegistrars() {
        return new ArrayList<>(SCHEDULED_TASK_REGISTRAR_MAP.values());
    }

    public static List<ScheduledExecutorService> getJobNames() {
        return new ArrayList<>(SCHEDULED_EXECUTOR_SERVICE_MAP.values());
    }

    public static void addScheduleJob(String jobName, ISchedulerJob job) {
        SCHEDULER_JOB_MAP.put(jobName, job);
    }

    public static void addScheduledTaskRegistrar(String jobName, ScheduledTaskRegistrar scheduledTaskRegistrar) {
        SCHEDULED_TASK_REGISTRAR_MAP.put(jobName, scheduledTaskRegistrar);
    }

    public static void addScheduledExecutorService(String jobName, ScheduledExecutorService scheduledExecutorService) {
        SCHEDULED_EXECUTOR_SERVICE_MAP.put(jobName, scheduledExecutorService);
    }

    public static ScheduledTaskRegistrar getScheduledTaskRegistrar(String jobName) {
        return SCHEDULED_TASK_REGISTRAR_MAP.get(jobName);
    }

    public static ScheduledExecutorService getScheduledExecutorService(String jobName) {
        return SCHEDULED_EXECUTOR_SERVICE_MAP.get(jobName);
    }

    public static ISchedulerJob getSchedulerJob(String jobName) {
        return SCHEDULER_JOB_MAP.get(jobName);
    }

    public static void removeScheduledTaskRegistrar(String jobName) {
        SCHEDULED_TASK_REGISTRAR_MAP.remove(jobName);
    }

    public static void removeScheduledExecutorService(String jobName) {
        SCHEDULED_EXECUTOR_SERVICE_MAP.remove(jobName);
    }

    public static void removeSchedulerJob(String jobName) {
        SCHEDULER_JOB_MAP.remove(jobName);
    }

    /**
     * 查看jobName是否已经存在
     */
    public static boolean existJobName(String jobName) {
        return SCHEDULED_TASK_REGISTRAR_MAP.containsKey(jobName) || SCHEDULED_EXECUTOR_SERVICE_MAP.containsKey(jobName);
    }

    public static void clear() {
        SCHEDULED_TASK_REGISTRAR_MAP.clear();
        SCHEDULED_EXECUTOR_SERVICE_MAP.clear();
        SCHEDULER_JOB_MAP.clear();
    }

    /**
     * 注册任务
     *
     * @param schedulerJob 任务信息
     */
    public static void registerJob(ISchedulerJob schedulerJob) {
        registerJob(schedulerJob.getJobName(), schedulerJob, schedulerJob.getJobCron());
    }

    /**
     * 注册任务
     *
     * @param jobName      任务名称
     * @param schedulerJob 任务信息
     */
    public static void registerJob(String jobName, ISchedulerJob schedulerJob) {
        registerJob(jobName, schedulerJob, schedulerJob.getJobCron());
    }

    /**
     * 注册任务
     *
     * @param jobName      任务名称
     * @param schedulerJob 任务信息
     * @param jobCron      任务cron
     */
    public static void registerJob(String jobName, ISchedulerJob schedulerJob, String jobCron) {
        log.info("定时任务本地自动配置启动,自动注册任务:{}", jobName);
        schedulerJob.init();
        final ScheduledTaskRegistrar taskRegistrar = new ScheduledTaskRegistrar();
        final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(schedulerJob.getScheduledThreadPoolCoreSize(),
                r -> {
                    Thread thread = new Thread(r);
                    thread.setName(schedulerJob.getScheduledThreadPrefix() + thread.getName());
                    return thread;
                });
        final TaskScheduler taskScheduler = new ConcurrentTaskScheduler(executorService);
        taskRegistrar.setTaskScheduler(taskScheduler);
        taskRegistrar.addCronTask(schedulerJob::execute, jobCron);
        taskRegistrar.afterPropertiesSet();
        SchedulerJobLocalContext.addScheduleJob(jobName, schedulerJob);
        SchedulerJobLocalContext.addScheduledTaskRegistrar(jobName, taskRegistrar);
        SchedulerJobLocalContext.addScheduledExecutorService(jobName, executorService);
    }

    /**
     * 销毁任务
     */
    public static void destroyJob(String jobName) {
        log.info("定时任务本地自动配置销毁,任务:{}", jobName);
        ScheduledTaskRegistrar scheduledTaskRegistrar = SchedulerJobLocalContext.getScheduledTaskRegistrar(jobName);
        ScheduledExecutorService scheduledExecutorService = SchedulerJobLocalContext.getScheduledExecutorService(jobName);
        Set<ScheduledTask> scheduledTasks = scheduledTaskRegistrar.getScheduledTasks();
        for (ScheduledTask scheduledTask : scheduledTasks) {
            scheduledTask.cancel(true);
        }
        // 暂停定时任务
        ISchedulerJob schedulerJob = SchedulerJobLocalContext.getSchedulerJob(jobName);
        schedulerJob.destroy();
        // 销毁线程池
        scheduledExecutorService.shutdown();
        if (scheduledExecutorService.isTerminated()) {
            // 销毁任务注册器
            scheduledTaskRegistrar.destroy();
            SchedulerJobLocalContext.removeScheduledTaskRegistrar(jobName);
            SchedulerJobLocalContext.removeScheduledExecutorService(jobName);
        }
    }
}
